package com.mju.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mju.dao.UserDao;
import com.mju.feign.clients.EmailClient;
import com.mju.pojo.User;
import com.mju.service.ex.*;
import com.mju.utils.JWTUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.*;

@Slf4j
@Service
public class UserServiceImpl implements IUserService {
  // 获取DAO层的接口
  @Autowired private UserDao userDao;
  @Autowired private EmailClient emailClient;

  @Override
  public boolean new_registor(User user) {
    // 获取用户名
    String username = user.getUsername();
    // 根据该用户名，尝试获取数据库里的用户名
    User result = userDao.selectByName(username);
    if (result != null) {
      log.error("用户名被占用，请重新输入");
      return false;
    }

    // 密码加密
    String oldPassword = user.getUserpassword();
    // 随机生成一个盐值，并将密码和盐值作为一个整体进行加密。
    String salt = UUID.randomUUID().toString().toUpperCase();
    String md5Password = getMd5Password(oldPassword, salt);
    user.setUserpassword(md5Password);
    // 补全，其余数据
    user.setIsDelete(2);
    user.setSalt(salt); // 一定要加入盐值
    user.setIsVip(0);

    //user.setAccountNumber(result.getAccountNumber());
    //user.setPayeeName(result.getPayeeName());

    // 补全：日志
    user.setCreatedUser(user.getUsername());
    user.setModifiedUser(user.getUsername());
    Date date = new Date();
    user.setCreatedTime(date);
    user.setModifiedTime(date);

    // 执行注册业务的逻辑
    int rows = userDao.insert(user);
    if (rows != 1) {
      log.error("注册失败...");
      return false;
    }


    // 发送邮件
    // 查询未激活用户是否创建成功
    User reslut = userDao.selectByName(user.getUsername());
    if (!Objects.isNull(reslut)) {
      // 生成有效期为一天的token
      Map<String, String> map = new HashMap<>();
      map.put("uid", String.valueOf(reslut.getId()));
      String token = JWTUtils.getADayJWT(map);

      emailClient.generateActivationUrl (token, reslut.getEmail());
      log.info("注册未激活用户成功");
    }
    return true;
  }

  /**
   * 修改用户状态
   *
   * @param uid
   * @param status
   * @return
   */
  @Override
  public boolean updateStatus(Integer uid, Integer status) {
    User user = userDao.selectById(uid);
    user.setIsDelete(status);
    return userDao.updateById(user) > 0;
  }

  @Override
  public void registor(User user) {
    // 获取用户名
    String username = user.getUsername();
    // 根据该用户名，尝试获取数据库里的用户名
    User result = userDao.selectByName(username);
    if (result != null) {
      // 跑出异常
      throw new UsernameDuplicatedException("用户名被占用，请重新选一个。");
    }

    // 密码加密
    String oldPassword = user.getUserpassword();
    // 随机生成一个盐值，并将密码和盐值作为一个整体进行加密。
    String salt = UUID.randomUUID().toString().toUpperCase();
    String md5Password = getMd5Password(oldPassword, salt);
    user.setUserpassword(md5Password);
    // 补全，其余数据
    user.setIsDelete(0);
    user.setSalt(salt); // 一定要加入盐值
    user.setIsVip(0);
    // 补全：日志
    user.setCreatedUser(user.getUsername());
    user.setModifiedUser(user.getUsername());
    Date date = new Date();
    user.setCreatedTime(date);
    user.setModifiedTime(date);

    // 执行注册业务的逻辑
    int rows = userDao.insert(user);
    if (rows != 1) {
      throw new InsertException("在用户注册过程中，产生了未知的异常。");
    }
  }

  @Override
  public User login(String username, String password) {
    // 查询用户是否存在于数据库中，不存在，抛出异常。
    User result = userDao.selectByName(username);
    if (result == null) {
      throw new UsernameNotFoundException("该用户不存在");
    }

    // 检测用户的密码是否匹配
    String oldPassword = result.getUserpassword();
    String salt = result.getSalt();
    String newPassword = getMd5Password(password, salt);
    // System.out.println("newPasw: "+newPassword);
    if (!newPassword.equals(oldPassword)) {
      throw new PasswordNotMatchException("用户密码错误");
    }

    // 判断下该用户数据是否被删除
    if (result.getIsDelete() == 1) {
      throw new UsernameNotFoundException("该用户不存在");
    }

    // 判断下该用户数据是否未激活
    if (result.getIsDelete() == 2) {
      throw new UsernameNotFoundException("该用户未激活");
    }

    // 封装需要返回的数据，供其他页面(通过session)显示
    // 目的：减少数据量
    User user = new User();
    user.setId(result.getId());
    user.setUsername(result.getUsername());
    user.setAvatar(result.getAvatar());
    user.setIsVip(result.getIsVip());
    return user;
  }

  @Override
  public void changePassword(Integer id, String username, String oldPassword, String newPassword) {
    // 根据uid，查询数据存不存在
    User result = userDao.selectById(id);
    // 数据不存在，或被管理员误删除了
    if (result == null || result.getIsDelete() == 1) {
      throw new UsernameNotFoundException("用户数据不存在");
    }
    // 对比下旧密码是否与数据库一致
    String oldMd5Password = getMd5Password(oldPassword, result.getSalt());
    if (!result.getUserpassword().equals(oldMd5Password)) {
      throw new PasswordNotMatchException("密码错误");
    }

    // 更新密码(盐值用原来的)
    String newMd5Password = getMd5Password(newPassword, result.getSalt());
    result.setUserpassword(newMd5Password);
    result.setModifiedUser(username);
    result.setModifiedTime(new Date());
    // 修改密码
    int rows = userDao.updateById(result);
    if (rows != 1) {
      throw new UpdateException("更新数据产生未知的异常");
    }
  }

  @Override
  public User getById(Integer id) {
    // 查询用户是否存在
    User result = userDao.selectById(id);
    if (result == null || result.getIsDelete() == 1) {
      throw new UsernameNotFoundException("用户数据不存在。");
    }
    // 封装个人资料需要的4个字段，返回回去，节省数据量
    User user = new User();
    user.setUsername(result.getUsername());
    user.setPhone(result.getPhone());
    user.setEmail(result.getEmail());
    user.setGender(result.getGender());
    user.setIsDelete(result.getIsDelete()); // 增加一个字段
    user.setAvatar(result.getAvatar()); // 增加一个字段
    user.setIsVip(result.getIsVip()); // 增加一个字段
    user.setAccountNumber(result.getAccountNumber());
    user.setPayeeName(result.getPayeeName());
    return user;
  }

  // 注意：
  //      1. id通过控制层的session里头的id给与
  //      2. user对象只有4个字段，springboot只会注入表单里的数据，需要手动添加id
  @Override
  public void changeInfo(Integer id, User user) {
    // 查询用户是否存在
    User result = userDao.selectById(id);
    if (result == null || result.getIsDelete() == 1) {
      throw new UsernameNotFoundException("用户数据不存在。");
    }
    user.setId(id); // 缺id，一定要补。
    user.setModifiedUser(user.getUsername());
    user.setModifiedTime(new Date());
    // 更新数据
    int rows = userDao.updateById(user);
    if (rows != 1) {
      throw new UpdateException("更新数据时，产生未知异常。");
    }
  }

  @Override
  public void changeAvatar(Integer id, String avatar, String username) {
    // 查询用户是否存在
    User result = userDao.selectById(id);
    if (result == null || result.getIsDelete() == 1) {
      throw new UsernameNotFoundException("用户数据不存在。");
    }
    // 更新头像数据、修改时间、修改人
    result.setAvatar(avatar);
    result.setModifiedUser(username);
    result.setModifiedTime(new Date());
    int rows = userDao.updateById(result);
    if (rows != 1) {
      throw new UpdateException("更新用户头像时，产生未知异常。");
    }
  }

  @Override
  public IPage<User> queryAllUsers(Integer currentPage, Integer pageSize) {
    IPage<User> page = new Page<>(currentPage, pageSize);
    userDao.selectPage(page, null);
    return page;
  }

  @Override
  public Integer deleteUserByUid(Integer uid) {
    //int rows = userDao.deleteById(uid);
    //if (rows != 1) {
    //  throw new DeleteException("删除异常");
    //}
    //return rows;
    // 逻辑删除
    User user = userDao.selectById(uid);
    user.setIsDelete(1);
    userDao.updateById(user);
    return 1;
  }

  @Override
  public Integer addUser(User user) {
    // 获取用户名
    String username = user.getUsername();
    // 根据该用户名，尝试获取数据库里的用户名
    User result = userDao.selectByName(username);
    if (result != null) {
      // 跑出异常
      throw new UsernameDuplicatedException("用户名被占用，请重新选一个。");
    }

    // 密码加密
    String oldPassword = user.getUserpassword();
    // 随机生成一个盐值，并将密码和盐值作为一个整体进行加密。
    String salt = UUID.randomUUID().toString().toUpperCase();
    String md5Password = getMd5Password(oldPassword, salt);
    user.setUserpassword(md5Password);
    // 补全，其余数据
    user.setIsDelete(0);
    user.setSalt(salt); // 一定要加入盐值
    // 补全：日志
    user.setCreatedUser(user.getUsername());
    user.setModifiedUser(user.getUsername());
    Date date = new Date();
    user.setCreatedTime(date);
    user.setModifiedTime(date);

    // 执行注册业务的逻辑
    int rows = userDao.insert(user);
    if (rows != 1) {
      throw new InsertException("在用户注册过程中，产生了未知的异常。");
    }
    return rows;
  }

  @Override
  public Integer updateIsVipAndVipName(Integer uid, Integer status, String vipName) {
    User user = userDao.selectById(uid);
    user.setIsVip(1);
    user.setVipName(vipName);
    return userDao.updateById(user);
  }

  @Override
  public Integer updateIsVip(Integer uid, Integer status) {
    User user = userDao.selectById(uid);
    user.setIsVip(1);
    return userDao.updateById(user);
  }

  @Override
  public Integer getUidByUname(String uname) {
    User user = userDao.selectByName(uname);
    return user.getId();
  }

  @Override
  public Integer updateUser(Integer uid, User user) {
    // 获取用户信息
    User result = userDao.selectById(uid);

    LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
    lqw.eq(User::getId, uid);
    user.setModifiedUser("管理员");
    user.setModifiedTime(new Date());

    System.out.println("修改用户1：" + user);
    // 密码加密
    // 更新密码(盐值用原来的)
    String newMd5Password = getMd5Password(user.getUserpassword(), result.getSalt());
    user.setUserpassword(newMd5Password);

    // 修改
    int rows = userDao.update(user, lqw);
    if(rows != 1) {
      throw new UpdateException("修改异常");
    }

    System.out.println("修改用户2：" + user);

    return rows;
  }

  @Override
  public void resetPassword(Integer uid) {
    User user = userDao.selectById(uid);
    // 设置默认密码
    String password = "mint"+user.getEmail();
    System.out.println(password);
    // 加密
    String newMd5Password = getMd5Password(password, user.getSalt());
    user.setUserpassword(newMd5Password);
    int rows = userDao.updateById(user);
    if(rows!= 1) {
      throw new UpdateException("修改异常");
    }
  }

  // 加密算法
  // 核心：盐值 + 密码 + 盐值
  private String getMd5Password(String password, String salt) {
    for (int i = 0; i < 3; i++) {
      password = DigestUtils.md5DigestAsHex((salt + password + salt).getBytes());
    }
    return password;
  }
}
